package chenji.itemeditor.itemeditor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import chenji.itemeditor.nbt.base.NBTBase;
import chenji.itemeditor.nbt.base.NBTTagCompound;
import chenji.itemeditor.nbt.base.NBTTagList;
import chenji.itemeditor.nbt.base.NBTTagString;
import chenji.itemeditor.util.NMSItem;

@SuppressWarnings("deprecation")
public class ItemEditor {
	private NMSItem nmsitem;
	private List<String> lore;
	private Map<Enchantment, Integer> enchantmentmap;
	private List<Attribute> attrs;
	private List<PotionEffect> effects;
	private List<String> pages;
	private List<FireworkExplosion> fireworkExplosion;

	public ItemEditor(ItemStack item) {
		nmsitem = NMSItem.getItem(item);
		this.loadEnchantment();
		this.loadLore();
		this.loadAttributes();
		this.loadPotionEffects();
		this.loadBookPage();
		this.loadFireworkExplosion();
	}

	public ItemStack getItem() {
		this.saveLore();
		this.saveEnchantment();
		this.saveAttributes();
		this.savePotionEffects();
		this.saveBookPage();
		this.saveFireworkExplosion();
		return this.nmsitem.getBukkitItem();
	}

	private ItemEditor loadEnchantment() {
		if (this.enchantmentmap != null) {
			return this;
		}
		this.enchantmentmap = Maps.newLinkedHashMap();
		NBTTagList enchs = (NBTTagList) nmsitem.getTag().get("ench");
		if (enchs == null) {
			this.enchantmentmap = Maps.newHashMap();
			return this;
		}
		for (NBTBase base : enchs.getList()) {
			if (base instanceof NBTTagCompound) {
				NBTTagCompound enchdata = (NBTTagCompound) base;
				int level = enchdata.getShort("lvl");
				int id = enchdata.getShort("id");

				Enchantment ench = Enchantment.getById(id);

				if (ench == null) {
					continue;
				}
				this.enchantmentmap.put(ench, level);
			}
		}
		return this;
	}

	private ItemEditor saveEnchantment() {
		NBTTagList enchs = new NBTTagList();
		for (Enchantment ench : this.enchantmentmap.keySet()) {
			int level = this.enchantmentmap.get(ench);
			NBTTagCompound enchdata = new NBTTagCompound();
			enchdata.setInt("id", ench.getId());
			enchdata.setInt("lvl", level);
			enchs.add(enchdata);
		}
		if (enchs.getList().isEmpty()) {
			this.nmsitem.getTag().set("ench", null);
		} else {
			this.nmsitem.getTag().set("ench", enchs);
		}
		return this;
	}

	public Map<Enchantment, Integer> getEnchantments() {
		return this.enchantmentmap;
	}

	public ItemEditor removeEnchantment(Enchantment ench) {
		this.enchantmentmap.remove(ench);
		return this;
	}

	public boolean containEnchantment(Enchantment ench) {
		return this.enchantmentmap.containsKey(ench);
	}

	public int getEnchantmentLevel(Enchantment ench) {
		if (this.enchantmentmap.containsKey(ench)) {
			return this.enchantmentmap.get(ench);
		}
		return -1;
	}

	public ItemEditor addEnchantment(int id, int level) {
		Enchantment m = Enchantment.getById(id);
		if (m == null) {
			return this;
		}
		this.enchantmentmap.put(m, level);
		return this;
	}

	public ItemEditor addEnchantment(Enchantment e, int lvl) {
		this.enchantmentmap.put(e, lvl);
		return this;
	}

	public ItemEditor clearEnchantment() {
		this.enchantmentmap.clear();
		return this;
	}

	public ItemEditor chengeEnchantmentLevel(Enchantment e, int level) {
		if (this.enchantmentmap.containsKey(e)) {
			this.enchantmentmap.put(e, level);
		}
		return this;
	}

	public ItemEditor setColor(int r, int g, int b) {
		int color = r * 65536 + g * 256 + b;
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		display.setInt("color", color);
		nmsitem.getTag().set("display", display);
		return this;
	}

	public ItemEditor addLoreLine(String line) {
		this.lore.add(line);
		return this;
	}

	public ItemEditor removeLoreLine(int line) {
		this.lore.remove(line);
		return this;
	}

	public ItemEditor clearLore() {
		this.lore = Lists.newArrayList();
		return this;
	}

	public ItemEditor setLore(List<String> lore) {
		if (lore == null) {
			throw new NullPointerException("lore不能为Null");
		}
		this.lore = lore;
		return this;
	}

	private ItemEditor saveLore() {
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		if (lore.isEmpty()) {
			display.set("Lore", null);
		} else {
			display.set("Lore", this.getStringNBTTagList(lore));
		}
		nmsitem.getTag().set("display", display);
		return this;
	}

	public List<String> getLore() {
		return this.lore;
	}

	private void loadLore() {
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		if (display == null) {
			this.lore = Lists.newArrayList();
			return;
		}
		NBTBase b = display.get("Lore");
		if (b == null) {
			this.lore = Lists.newArrayList();
			return;
		}
		if (!(b instanceof NBTTagList)) {
			this.lore = Lists.newArrayList();
			return;
		}
		this.lore = this.getStringArrayList((NBTTagList) b);
	}

	private void loadPotionEffects() {
		NBTTagList t = (NBTTagList) this.nmsitem.getTag().getList("CustomPotionEffects");
		if (t == null) {
			this.effects = Lists.newArrayList();
			return;
		}
		List<PotionEffect> list = Lists.newArrayList();
		for (NBTBase b : t.getList()) {
			if (!(b instanceof NBTTagCompound)) {
				continue;
			}
			NBTTagCompound c = (NBTTagCompound) b;
			PotionEffect e = this.loadCustomPotionEffect(c);
			if (e == null) {
				continue;
			}
			list.add(e);
		}
		this.effects = list;
	}

	private void loadFireworkExplosion() {
		NBTTagCompound n = this.nmsitem.getTag().getCompound("Fireworks");
		if (n == null) {
			this.fireworkExplosion = Lists.newArrayList();
			return;
		}
		if (n.isEmpty()) {
			this.fireworkExplosion = Lists.newArrayList();
			return;
		}
		NBTTagList list = n.getList("Explosions");
		if (list == null) {
			this.fireworkExplosion = Lists.newArrayList();
			return;
		}
		this.fireworkExplosion = Lists.newArrayList();
		for (NBTBase b : list.getList()) {
			if (!(b instanceof NBTTagCompound)) {
				continue;
			}
			NBTTagCompound nbt = (NBTTagCompound) b;
			FireworkExplosion e = new FireworkExplosion();
			if (e.loadFromNBTTagCompound(nbt) != null) {
				this.fireworkExplosion.add(e);
			}
		}

	}

	private void loadBookPage() {
		NBTTagList t = (NBTTagList) this.nmsitem.getTag().getList("pages");
		if (t == null) {
			this.pages = Lists.newArrayList();
			return;
		}
		List<String> pages = this.getStringArrayList(t);
		if (pages == null) {
			this.pages = Lists.newArrayList();
		} else {
			this.pages = pages;
		}

	}

	private void saveFireworkExplosion() {
		NBTTagList n = new NBTTagList();
		for (FireworkExplosion exp : this.fireworkExplosion) {
			n.add(exp.getTag());
		}
		NBTTagCompound nbt = this.nmsitem.getTag().getCompound("Fireworks");
		if (n.getList().isEmpty()) {
			nbt.set("Explosions", null);
		} else {
			nbt.set("Explosions", n);
		}
	}

	private void saveBookPage() {
		NBTTagList n = this.getStringNBTTagList(this.pages);
		if (n.getList().isEmpty()) {
			this.nmsitem.getTag().set("pages", null);
		} else {
			this.nmsitem.getTag().set("pages", n);
		}

	}

	private void savePotionEffects() {
		NBTTagList s = new NBTTagList();
		for (PotionEffect a : this.effects) {
			s.add(this.asCustomPotionEffect(a));
		}

		if (s.getList().isEmpty()) {
			this.nmsitem.getTag().set("CustomPotionEffects", null);
		} else {
			this.nmsitem.getTag().set("CustomPotionEffects", s);
		}
	}

	private NBTTagList getStringNBTTagList(List<String> lore) {
		NBTTagList lorelist = new NBTTagList();
		for (String s : lore) {
			lorelist.add(new NBTTagString(s));
		}
		return lorelist;
	}

	private ArrayList<String> getStringArrayList(NBTTagList s) {
		ArrayList<String> a = Lists.newArrayList();
		for (NBTBase b : s.getList()) {
			if (b instanceof NBTTagString) {
				a.add(((NBTTagString) b).getValue());
			}
		}
		return a;
	}

	public ItemEditor setDisplayName(String name) {
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		display.setString("Name", name);
		this.nmsitem.getTag().set("display", display);
		return this;
	}

	public ItemEditor clearDisplayName() {
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		display.set("Name", null);
		this.nmsitem.getTag().set("display", display);
		return this;
	}

	public ItemEditor clearColor() {
		NBTTagCompound display = nmsitem.getTag().getCompound("display");
		display.set("Color", null);
		this.nmsitem.getTag().set("display", display);
		return this;
	}

	public ItemEditor clearTag() {
		this.nmsitem.setTag(new NBTTagCompound());
		return this;
	}

	public ItemEditor setUnbreakable(boolean b) {
		this.nmsitem.getTag().setInt("Unbreakable", b ? 1 : 0);
		return this;
	}

	public boolean isUnbreakable() {
		return this.nmsitem.getTag().getBoolean("Unbreakable");
	}

	public ItemEditor addAttrbute(Attribute b) {
		this.attrs.add(b);
		return this;
	}

	public ItemEditor removeAttirbute(AttributeType t) {
		Iterator<Attribute> iter = this.attrs.iterator();
		while (iter.hasNext()) {
			Attribute attr = iter.next();
			if (attr.getType().equals(t)) {
				iter.remove();
			}
		}
		return this;
	}

	public boolean containAttribute(AttributeType t) {
		for (Attribute a : this.attrs) {
			if (a.getType().equals(t)) {
				return true;
			}
		}
		return false;
	}

	public List<Attribute> getAttirbutes() {
		return this.attrs;
	}

	public ItemEditor clearAttribute() {
		this.attrs.clear();
		return this;
	}

	private void loadAttributes() {
		NBTTagList t = (NBTTagList) this.nmsitem.getTag().getList("AttributeModifiers");
		if (t == null) {
			this.attrs = Lists.newArrayList();
			return;
		}
		List<Attribute> list = Lists.newArrayList();
		for (NBTBase b : t.getList()) {
			if (!(b instanceof NBTTagCompound)) {
				continue;
			}
			NBTTagCompound c = (NBTTagCompound) b;
			Attribute a = new Attribute();
			if (a.loadFromNBTTagCompound(c) == null) {
				continue;
			}
			list.add(a);
		}
		this.attrs = list;
	}

	private void saveAttributes() {
		NBTTagList s = new NBTTagList();
		for (Attribute a : this.attrs) {
			s.add(a.getNBT());
		}
		if (s.getList().isEmpty()) {
			this.nmsitem.getTag().set("AttributeModifiers", null);
		} else {
			this.nmsitem.getTag().set("AttributeModifiers", s);
		}
	}

	public void clearItemEditorData() {
		this.nmsitem.getTag().set("ItemEditor", null);
	}

	public NBTTagCompound loadItemEditorData() {
		return this.nmsitem.getTag().getCompound("ItemEditor");
	}

	public ItemEditor setItemEditorData(NBTTagCompound tag) {
		this.nmsitem.getTag().set("ItemEditor", tag);
		return this;
	}

	public ItemEditor setHideFlags(int flags) {
		this.nmsitem.getTag().setInt("HideFlags", flags);
		return this;
	}

	public String getSkullOwner() {
		return this.nmsitem.getTag().getString("SkullOwner");
	}

	public HideFlagsSet getHideFlags() {
		int i = this.getHideFlag();
		return new HideFlagsSet(i);
	}

	public ItemEditor setHideFlags(HideFlagsSet flags) {
		this.nmsitem.getTag().setInt("HideFlags", flags.getValue());
		return this;
	}

	public ItemEditor setSkullOwner(String owner) {
		this.nmsitem.getTag().setString("SkullOwner", owner);
		return this;
	}

	public int getHideFlag() {
		return this.nmsitem.getTag().getInt("HideFlags");
	}

	public ItemEditor setAmount(int amount) {
		this.nmsitem.setCount(amount);
		return this;
	}

	public ItemEditor setData(int data) {
		this.nmsitem.setData(data);
		return this;
	}

	public ItemEditor setRepairCost(int repaircost) {
		this.nmsitem.setRepairCost(repaircost);
		return this;
	}

	public NBTTagCompound asCustomPotionEffect(PotionEffect e) {
		NBTTagCompound b = new NBTTagCompound();
		b.setInt("Id", e.getType().getId());
		b.setInt("Amplifier", e.getAmplifier());
		b.setInt("Duration", e.getDuration());
		b.setBoolean("Ambient", e.isAmbient());
		b.setBoolean("ShowParticles", e.hasParticles());
		return b;
	}

	public PotionEffect loadCustomPotionEffect(NBTTagCompound n) {
		int id = n.getInt("Id");
		PotionEffectType t = PotionEffectType.getById(id);
		if (t == null) {
			return null;
		}
		int amplifier = n.getInt("Amplifier");
		int duration = n.getInt("Duration");
		boolean ambient = n.getBoolean("Ambient");
		boolean showparticles = n.getBoolean("ShowParticles");
		return new PotionEffect(t, amplifier, duration, ambient, showparticles);

	}

	public ItemEditor addPotionEffect(PotionEffect effect) {
		this.effects.add(effect);
		return this;
	}

	public ItemEditor removePotionEffect(PotionEffect e) {
		this.effects.remove(e);
		return this;
	}

	public ItemEditor removePotionEffect(PotionEffectType e) {
		Iterator<PotionEffect> iter = this.effects.iterator();
		while (iter.hasNext()) {
			PotionEffect attr = iter.next();
			if (attr.getType().equals(e)) {
				iter.remove();
			}
		}
		return this;
	}

	public ItemEditor addPotionEffect(NBTTagCompound c) {
		PotionEffect e = this.loadCustomPotionEffect(c);
		if (e != null) {
			this.effects.add(e);
		}
		return this;
	}

	public ItemEditor setPotionEffects(List<PotionEffect> effects) {
		if (effects != null) {
			this.effects = effects;
		}
		return this;
	}

	public ItemEditor setEnchantmentMap(Map<Enchantment, Integer> map) {
		if (map != null) {
			this.enchantmentmap = map;
		}
		return this;
	}

	public ItemEditor setAttributes(List<Attribute> attributes) {
		if (attributes != null) {
			this.attrs = attributes;
		}
		return this;
	}

	public List<Attribute> getAttributes() {
		return this.attrs;
	}

	public ItemEditor setDefaultPotion(PotionEffect e) {
		if (e == null) {
			return this;
		}
		NBTTagCompound n = this.asCustomPotionEffect(e);
		this.nmsitem.getTag().set("Potion", n);
		return this;
	}

	public PotionEffect getDefaultPotion() {
		NBTBase b = this.nmsitem.getTag().get("Potion");
		if (b == null) {
			return null;
		}
		if (!(b instanceof NBTTagCompound)) {
			return null;
		}
		NBTTagCompound c = (NBTTagCompound) b;
		PotionEffect e = this.loadCustomPotionEffect(c);
		if (e == null) {
			return null;
		}
		return e;
	}

	public ItemEditor setResolved(int resolved) {
		this.nmsitem.getTag().setInt("resolved", resolved);
		return this;
	}

	public ItemEditor setTitle(String title) {
		this.nmsitem.getTag().setString("title", title);
		return this;
	}

	public ItemEditor setAuthor(String author) {
		this.nmsitem.getTag().setString("author", author);
		return this;
	}

	public ItemEditor setGeneration(int i) {
		this.nmsitem.getTag().setInt("generation", i);
		return this;
	}

	public int getGeneration() {
		return this.nmsitem.getTag().getInt("generation");
	}

	public int getResolved() {
		return this.nmsitem.getTag().getInt("resolved");
	}

	public String getTitle() {
		return this.nmsitem.getTag().getString("title");
	}

	public String getAuthor() {
		return this.nmsitem.getTag().getString("author");
	}

	public List<String> getPages() {
		return this.pages;
	}

	public ItemEditor setPages(List<String> pages) {
		this.pages = pages;
		return this;
	}

	public ItemEditor addPage(String page) {
		this.pages.add(page);
		return this;
	}

	public ItemEditor removePage(int index) {
		if (index > this.pages.size() - 1) {
			return this;
		}
		this.pages.remove(index);
		return this;
	}

	public ItemEditor addExplosion(FireworkExplosion exp) {
		this.fireworkExplosion.add(exp);
		return this;
	}

	public ItemEditor removeExplosion(FireworkExplosion exp) {
		this.fireworkExplosion.remove(exp);

		return this;
	}

	public List<FireworkExplosion> getExplosions() {
		return this.fireworkExplosion;
	}

	public ItemEditor removeExplosion(FireworkType t) {
		Iterator<FireworkExplosion> iter = this.fireworkExplosion.iterator();
		while (iter.hasNext()) {
			FireworkExplosion expl = iter.next();
			if (expl.getType().equals(t)) {
				iter.remove();
			}
		}
		return this;
	}

	public ItemEditor setExplosion(FireworkExplosion e) {
		this.nmsitem.getTag().set("Explosion", e.getTag());
		return this;
	}

	public FireworkExplosion getExplosion() {
		NBTTagCompound n = this.nmsitem.getTag().getCompound("Explosion");
		FireworkExplosion fe = new FireworkExplosion();
		if (fe.loadFromNBTTagCompound(n) == null) {
			return null;
		}
		return fe;
	}

	public ItemEditor setFlightTime(int time) {
		if (time <= 0) {
			time = 1;
		}
		if (time > 3) {
			time = 3;
		}
		NBTTagCompound nbt = this.nmsitem.getTag().getCompound("Fireworks");
		nbt.setInt("Flight", time);
		this.nmsitem.getTag().set("Fireworks", nbt);
		return this;
	}

	public ItemEditor removeAttirbute(int loc) {
		if (loc > 0 || loc <= this.attrs.size() - 1) {
			this.attrs.remove(loc);
		}
		return this;

	}

}